﻿using System;
using System.IO;
using System.Text;
using Interface;

namespace Client
{
    /// <summary>
    /// unity日志系统
    /// </summary>
    internal class UnityLogger : ILogger
    {
        /// <summary>
        /// 仅在编辑器下或debug编译模式下，输出Debug日志
        /// </summary>
        public bool EnableLogDebug;

        /// <summary>
        /// 是否启用Info（Error和Warning都是始终启用的）
        /// </summary>
        public bool EnableLogInfo;

        /// <summary>
        /// 日志是否追加时间信息
        /// </summary>
        public bool EnableTime = true;

        /// <summary>
        /// 是否允许保存日志，即把日志写入到文件中
        /// </summary>
        public bool EnableSaveToFile = false;

        /// <summary>
        /// 是否同步采用Unity的日志输出（LogError必定同步到Unity的日志输出）
        /// </summary>
        public bool EnableUnityLog = false;

        /// <summary>
        /// 默认是否输出堆栈
        /// </summary>
        public bool DefaultEnableStack = false;

        /// <summary>
        /// 日志输出到的目录
        /// </summary>
        private string LogFileDir = UnityEngine.Application.persistentDataPath + "/Log/";

        /// <summary>
        /// 用于向文件写日志
        /// </summary>
        private StreamWriter LogFileWriter = null;

        private StringBuilder sb;

        public UnityLogger(bool EnableLogDebug, bool EnableLogInfo, bool EnableUnityLog, bool DefaultEnableStack)
        {
            this.EnableLogDebug = EnableLogDebug;
            this.EnableLogInfo = EnableLogInfo;
            this.EnableUnityLog = EnableUnityLog;
            this.DefaultEnableStack = DefaultEnableStack;

            sb = new StringBuilder(1024);
        }

        private string Prepare(string category, string message)
        {
            sb.Clear();
            sb.Append(category);
            sb.Append(' ');
            if (EnableTime)
            {
                sb.Append(DateTime.Now.ToString("HH:mm:ss.fff"));
                sb.Append(' ');
            }
            sb.Append(message);
            return sb.ToString();
        }
        private string Prepare(string category, string format, params object[] args)
        {
            sb.Clear();
            sb.Append(category);
            sb.Append(' ');
            if (EnableTime)
            {
                sb.Append(DateTime.Now.ToString("HH:mm:ss.fff"));
                sb.Append(' ');
            }
            sb.AppendFormat(format, args);
            return sb.ToString();
        }

        private void SetupLogFileWriter()
        {
            if (LogFileWriter == null)
            {
                var LogFileName = DateTime.Now.GetDateTimeFormats('s')[0].ToString();
                LogFileName = LogFileName.Replace("-", "_");
                LogFileName = LogFileName.Replace(":", "_");
                LogFileName = LogFileName.Replace(" ", "");
                LogFileName = LogFileName + ".log";

                string path = LogFileDir + LogFileName;
                try
                {
                    if (!Directory.Exists(LogFileDir))
                    {
                        Directory.CreateDirectory(LogFileDir);
                    }
                    LogFileWriter = File.AppendText(path);
                    LogFileWriter.AutoFlush = true;
                }
                catch (Exception ex)
                {
                    LogFileWriter = null;
                    UnityEngine.Debug.Log("SetupLogFileWriter get exception: " + ex.Message + ex.StackTrace);
                }
            }
        }

        /// <summary>
        /// 将日志写入到文件中
        /// </summary>
        /// <param name="message"></param>
        /// <param name="EnableStack"></param>
        private void LogToFile(string message, bool enableStack)
        {
            if (LogFileWriter == null)
            {
                SetupLogFileWriter();
            }

            if (LogFileWriter != null)
            {
                try
                {
                    LogFileWriter.WriteLine(message);

                    if (enableStack || DefaultEnableStack)
                    {
                        LogFileWriter.WriteLine(UnityEngine.StackTraceUtility.ExtractStackTrace());
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private void LogInfoToUnity(string message)
        {
            UnityEngine.Debug.Log(message);
        }
        private void LogWarningToUnity(string message)
        {
            UnityEngine.Debug.LogWarning(message);
        }
        private void LogErrorToUnity(string message)
        {
            UnityEngine.Debug.LogError(message);
        }

        public void Debug(object message)
        {
            if (!EnableLogDebug)
            {
                return;
            }

            var s = Prepare("[D]", message.ToString());

            if (EnableUnityLog)
            {
                LogInfoToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Debug(string format, params object[] args)
        {
            if (!EnableLogDebug)
            {
                return;
            }

            var s = Prepare("[D]", format, args);

            if (EnableUnityLog)
            {
                LogInfoToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Info(object message)
        {
            if (!EnableLogInfo)
            {
                return;
            }

            var s = Prepare("[I]", message.ToString());

            if (EnableUnityLog)
            {
                LogInfoToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Info(string format, params object[] args)
        {
            if (!EnableLogInfo)
            {
                return;
            }

            var s = Prepare("[I]", format, args);

            if (EnableUnityLog)
            {
                LogInfoToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Warning(object message)
        {
            var s = Prepare("[W]", message.ToString());

            if (EnableUnityLog)
            {
                LogWarningToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Warning(string format, params object[] args)
        {
            var s = Prepare("[W]", format, args);

            if (EnableUnityLog)
            {
                LogWarningToUnity(s);
            }

            if (EnableSaveToFile)
            {
                LogToFile(s, false);
            }
        }

        public void Error(object message)
        {
            var s = Prepare("[E]", message.ToString());

            LogErrorToUnity(s);

            if (EnableSaveToFile)
            {
                LogToFile(s, true);
            }
        }

        public void Error(string format, params object[] args)
        {
            var s = Prepare("[E]", format, args);

            LogErrorToUnity(s);

            if (EnableSaveToFile)
            {
                LogToFile(s, true);
            }
        }
    }
}
